package com.aldobucchi.graph.query.composite
{
	import com.adobe.utils.ArrayUtil;
	
	import flash.events.EventDispatcher;
	
	import mx.rpc.events.ResultEvent;
	
	import com.aldobucchi.graph.query.IQueryTarget;
	import com.aldobucchi.graph.query.Query;
	import com.aldobucchi.graph.query.QueryEvent;
	import com.aldobucchi.utils.Arc;





	/**
	 * 
	 * 
	 * 
	 * 
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class TransitiveClosureQuery extends EventDispatcher
	{

		
		private var arc:Arc;
		
		
		
		private var target:IQueryTarget;
		
		private var priority:int;
		

		private var startingNode:*;

		
		
		private var pendingQueries:Array = [];
		
		private var accumulatedNodes:Array = [];
		
		
		
		
		private var canceled:Boolean = false;
		
		
		
		public function TransitiveClosureQuery( startingNode:*, arc:Arc, target:IQueryTarget=null , priority:int=5, includeStartingNode:Boolean=false )
		{

			this.startingNode = startingNode;
			this.arc 		= arc;
			this.target 	= target;
			this.priority 	= priority;
			
			if ( includeStartingNode )
				accumulatedNodes.push( startingNode );
			
		}
		
		
		
		public function execute( ):void
		{
			processNode( startingNode );
		}
		
		
		public function cancel( ):void
		{
			canceled = true;
			
			for each ( var q:Query in pendingQueries )
				q.cancel( );
			
		}
		
		
		
		private function processNode( node:* ):void
		{
			
			if ( canceled )
				return;
				
			
			// trace( node.stringForm );
			var query:Query;

			query = new Query( target, priority );
			
			query.simpleQueryNode 	= node;
			query.simpleQueryArc 	= arc;			

			query.addEventListener( QueryEvent.RESULT, query_result, false, 0, true );
			
			pendingQueries.push( query );
			
			query.execute( );
			

		}
		
		
		
		private function query_result( event:QueryEvent ):void
		{


			if ( canceled )
				return;
				

			var len:int = accumulatedNodes.length;

			try {
				
				for each ( var child:* in event.target.result )
				{
					// trace( ".. " + child.stringForm );
					accumulatedNodes.push( child );							
					processNode( child );
				}


			} catch( e:Error ){	}			
		

			ArrayUtil.removeValueFromArray( pendingQueries, event.target );

			if ( pendingQueries.length == 0 )
			{
				// we are done
				dispatchEvent( new ResultEvent( ResultEvent.RESULT, false, true, accumulatedNodes ) );

			}
			

		
		}
		
	}

}